// Awaited;

type AwaitedDemo = Awaited<Promise<string>>;

type AwaitedDemo2 = Awaited<Promise<Promise<number>>>; // number, 这家伙可以是嵌套使用，直到拿到最后一层

type Ac = Awaited<boolean | Promise<number>>; // boolean | number; 可以把 Promise 这一层干掉；

// ConstructorParameters;
// 返回构造方法的元组
// 主要是用来得到构建方法的元组, 类型里面一定要是构造方法
type ConsType = ConstructorParameters<
  new (name: string, age?: number) => object
>; // [name: string, age?: number | undefined]

type PersonType = ConstructorParameters<FunctionConstructor>; // string[]

// Exclude<UnionType, ExcludedMembers>; 主要是从联合类型中删除不需要的类型
//
type T1 = Exclude<"a" | "b" | "c", "a">; // 'b'|'c'
type T2 = Exclude<"a" | "b" | "c", "a" | "b">; // 'c'
type T3 = Exclude<string | (() => void), Function>; // string
type T4 = Exclude<string | string[], any[]>; // string
type T5 = Exclude<(() => void) | null, Function>; // null
type T6 = Exclude<200 | 400, 200 | 201>; // 400
type T7 = Exclude<number, boolean>; // number

// Extract<Type, Union>;
// 用来取 Type 和 Union 的交集,这里的 Type 和 Union 都是联合类型

type T11 = Extract<"a" | "b" | "c", "a">; // 'a'
type T21 = Extract<"a" | "b" | "c", "a" | "b">; // 'a'|'b'
type T31 = Extract<"a" | "b" | "c", "a" | "d">; // 'a'
type T41 = Extract<string | string[], any[]>; // string[]
type T51 = Extract<(() => void) | null, Function>; // () => void
type T61 = Extract<200 | 400, 200 | 201>; // 200

// InstanceType<Type>; 获取构建函数的返回值类型； 相当于ReturnType
class MyP {
  constructor() {}
}
type MyInsType = InstanceType<typeof MyP>; // 返回MyP 本身

type MyInsType2 = InstanceType<new () => number>; // number

// NonNullable<Type>;
// 这也针对的联合类型，踢出联合类型中的 null 和 undefined
// string|number
type T12 = NonNullable<string | number | undefined>;

// string[]
type T22 = NonNullable<string[] | null | undefined>;
type T32 = NonNullable<boolean>; // boolean
type T43 = NonNullable<number | null>; // number
type T52 = NonNullable<string | undefined>; // string
type T62 = NonNullable<null | undefined>; // never

// Omit<Type, Keys>;
// 用来剔除掉类型中不需要的 Keys

type User = {
  name: string;
  age?: number;
  addr: string;
};

interface Glass {
  a: string;
  b: number;
  c: string;
}

class MyPerson {
  static sayHi(name: string) {
    alert(`hello` + name);
    return name;
  }
}

const myMMM = {
  name: "zhangsan",
  age: 19,
  isMarry: false,
  addr: "mmmm",
};

type MyObjType = typeof myMMM;

type PersonHi = typeof MyPerson.sayHi;

type userOmitAge = Omit<User, "age" | "addr">; // {name: string}

type GlassOmit = Omit<Glass, "a" | "b" | "c">; // {}

const mathRandom = Array.isArray;

type mathRandomType = typeof mathRandom;

// Parameters<Type> 从函数类型Type里面提取参数类型，并返回一个元组
type Pt1 = Parameters<() => void>;
type Pt2 = Parameters<(name: string, age: number, habbid?: boolean) => void>;

const pt2Ins: Pt2 = ["zhangsan", 123, false];
console.log(pt2Ins);

// Partial<Type> 把Type 中所有属性变成可选属性
type AA = {
  x: number;
  y: number;
  z: string;
};

/**
  type AAPartial = {
    x?: number | undefined;
    y?: number | undefined;
    z?: string | undefined;
}
*/
type AAPartial = Partial<AA>;

// Pick<TYpe, Keys> 从TYpe 里面选中指定的Keys 组成一个新的类型和Omit相反

/**
 * type myPick = {
    z: string;
    x: number;
}
*/
type myPick = Pick<AA, "z" | "x">;

// Readonly<Type>返回一个新类型，将参数类型Type的所有属性变为只读属性
/**
 type AAReadonly = {
    readonly x: number;
    readonly y: number;
    readonly z: string;
}
 */
type AAReadonly = Readonly<AA>;
// 小节： 把 AA 变成只读的可选情怀
// type AAPartialReadonly = {
//   readonly x?: number | undefined;
//   readonly y?: number | undefined;
//   readonly z?: string | undefined;
// };
// 这些类型是可以嵌套使用的
type AAPartialReadonly = Readonly<Partial<AA>>;

// Record<Keys, Type>  这个返回一个对象类型，参数是keys 用做键名，type用作键值类型
//
// type myRecord = {
//   name: string;
// };
type myRecord = Record<"name", string>;
// type myRecord4 = {
//   name: "mmm";
// };
type myRecord4 = Record<"name", "mmm">;
// type myRecord2 = {
//   name: string;
//   age: string;
// };
type myRecord2 = Record<"name" | "age", string>;
// type myRecord3 = {
//   name: string | number | Function;
//   age: string | number | Function;
// };
type myRecord3 = Record<"name" | "age", string | number | Function>;
// type myRecord5 = {
//   a: string;
//   b: string;
//   c: string;
// };
type myRecord5 = Record<keyof Glass, string>;

// 只能这么定义
const Record4: myRecord4 = {
  name: "mmm",
};

// Required<Type>;
// Required<Type>返回一个新类型，将参数类型Type的所有属性变为必选属性。它与Partial<Type>的作用正好相反。

type BB = {
  x?: number;
  y?: string;
  m: string;
};

// type BBRequire = {
//   x: number;
//   y: string;
//   m: string;
// };
type BBRequire = Required<BB>;

// ReadonlyArray<Type> 用来生成一个只读数组类型，类型参数Type表示数组成员的类型。

const valuseMM: ReadonlyArray<number> = [1, 2, 3, 45, 5, 6];

// 以下的操作就不能玩了；因为这个数组是个只读的，就不能进行push/pop/shift/unshift/splice
// valuseMM.push(123);
// ReturnType<Type>提取函数类型Type的返回值类型，作为一个新类型返回
// valuseMM.splice(2, 1);

function Myfunc(): void;
function Myfunc(name?: string): string;

function Myfunc(name?: number): number;

function Myfunc(name?: string | number | undefined): string | number | void {
  if (typeof name === "string") {
    return name;
  }

  return name;
}

// Myfunc();
// Myfunc("zhangsan");
// Myfunc(123);
//
type MyfuncType = ReturnType<typeof Myfunc>;

type MyfuncType2 = ReturnType<() => number>;

// ThisType<Type>不返回类型，只用来跟其他类型组成交叉类型，用来提示 TypeScript 其他类型里面的this的类型
// 用来告诉函数内部this的类型的

type userInsType = {
  name: string;
  age: number;
  addr?: string;
};

// 定义这个MyThisFunc让里面的this 的指向 userInsType
// function MyThisFunc() {
//   console.log(this);
//   return this;
// }
//
function show(name: string): string;

function show(name: string): string {
  console.log(name);
  return "abc";
}

type FUnctionType = { [name: string]: Function } & ThisType<userInsType>;

let show2: { [name: string]: Function } & ThisType<userInsType> = {
  show(name: string) {
    console.log(name);
    this.name;
  },
};

function show33(namee: string): number;

// 要是一个函数的时候,函数的第一个参数可以指定 this 指向,如下所示;
function show33(this: userInsType, namee: string): number {
  console.log(namee);
  console.log(this);
  return 123;
}

show33.call(
  {
    name: "zhangsan",
    age: 18,
    addr: "this is a test",
  },
  "zhangsan",
);
show33("zhgnsan");

//
// let show3: show3Type = function () {
//   this.name;
//
//   return "";
// };
//
////const myInstall: userInsType = {
//  name: "xhangsan",
//  age: 14,
//};
//
// show3.call(myInstall);
//
// ThisParameterType<Type>提取函数类型中this参数的类型。

function toHex(this: number) {
  return this.toString(16);
}

type TTT = ThisParameterType<typeof toHex>; // number

// OmitThisParameter<Type>从函数类型中移除 this 参数。

function MyToHex(this: Number, name: string, age: number): string {
  console.log(this);
  console.log(name);
  console.log(age);
  return "";
}

//  这个时候就获取了函数类型
type MyToHexType = typeof MyToHex;

// 得到this的类型
type MyToHexThisType = ThisParameterType<MyToHexType>; // Number

// 除 this 以外的参数类型
type MyToHexExceptThisType = OmitThisParameter<MyToHexType>; // (name: string, age: number) => string

type MyToHexExceptThisArgsType = Parameters<MyToHexExceptThisType>;

type ValuesMM = MyToHexExceptThisArgsType[number];

type MyValIns = {
  name: ValuesMM;
  age: ValuesMM;
};

const myObj: MyValIns = {
  name: "zyangsan",
  age: 34,
};

console.log(myObj);

// Uppercase<StringType>将字符串类型的每个字符转为大写。
// Lowercase<StringType>将字符串的每个字符转为小写。
// Capitalize<StringType>将字符串的第一个字符转为大写。首字母大写
// Uncapitalize<StringType> 将字符串的第一个字符转为小写。首字母小写
